/*
  Srt2Writ (Sample Writ encoder)
  (c)2007 Roman Vorobets
*/
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <locale.h>
#include <ogg/ogg.h>
#include <writ/writ.h>

/*
  Basic UTF-8 manipulation routines
  by Jeff Bezanson
*/
static int u8_toutf8(char *dest, int destsz, unsigned short *src, int srcsz)
{
  unsigned short ch;
  int i = 0;
  char *dest_end = dest + destsz;

  while (srcsz < 0 ? src[i] != 0 : i < srcsz) {
    ch = src[i];
    if (ch < 0x80) {
      if (dest >= dest_end) return i;
      *dest++ = (char)ch;
    } else if (ch < 0x800) {
      if (dest >= dest_end - 1) return i;
      *dest++ = (ch >> 6) | 0xC0;
      *dest++ = (ch & 0x3F) | 0x80;
    } else {
      if (dest >= dest_end - 2) return i;
      *dest++ = (ch >> 12) | 0xE0;
      *dest++ = ((ch >> 6) & 0x3F) | 0x80;
      *dest++ = (ch & 0x3F) | 0x80;
    }
    i++;
  }
  if (dest < dest_end) *dest = '\0';
  return i;
}

static int ogg_page_write(ogg_page *og, FILE *f)
{
  return
    og->header_len == fwrite(og->header, 1, og->header_len, f) &&
    og->body_len == fwrite(og->body, 1, og->body_len, f);
}

static ogg_int32_t conv_time(int time[4])
{
  return 1000L * (60L * (60L * time[0] + time[1]) + time[2]) + time[3];
}

void main(int argc, char *argv[])
{
  FILE *fin, *fout;
  ogg_stream_state os;
  ogg_page og;
  ogg_packet op;
  writ_state ws;
  int count, prev_seq, seq, time_s[4], time_e[4];
  char text[257], utf8_text[769], *ptail;
  wchar_t wide_text[256];
  ogg_int32_t start, prev_start, end;

  setlocale(LC_ALL, "");
  printf(
    "\nSubRip to Writ subtitles convertor\n"
    "(c)2007 Roman Vorobets\n\n"
    );
  if (3 != argc)
  {
    printf("usage: srt2writ <infile.srt> <outfile.ogg>\n");
    exit(0);
  }
  fin = fopen(argv[1], "r");
  fout = fopen(argv[2], "wb");
  if (NULL == fin)
  {
    printf("Error: can't open input file\n");
    exit(1);
  }
  if (NULL == fout)
  {
    printf("Error: can't create output file\n");
    exit(1);
  }
  srand((unsigned)time(NULL));
  if (-1 == ogg_stream_init(&os, rand() ^ (rand() << 15) ^ (rand() << 30)))
  {
    printf("Error: stream init failed\n");
    exit(1);
  }
  ogg_stream_setdiscont(&os);
  writ_encode_init(&ws, 1, 1000);
  writ_encode_header(&ws, &op);
  ogg_stream_packetin(&os, &op);
  while (ogg_stream_flush(&os, &og))
  {
    if (!ogg_page_write(&og, fout))
    {
      printf("Error: failed writing header to output stream\n");
      exit(1);
    }
    /*
    No multiple languages & windows support in SubRip, don't need this:
    while (1 == writ_encode_header(&ws, &op))
      ogg_stream_packetin(&os, &op);
    */
  }
  prev_seq = 0;
  prev_start = -1;
  while (EOF != (count = fscanf(fin, "%d", &seq)))
  {
    if (prev_seq)
    {
      ogg_stream_packetin(&os, &op);
    }
    if (1 != count ||
      seq != 1 + prev_seq ||
      '\n' != fgetc(fin) ||
      8 != fscanf(fin, "%2d:%2d:%2d,%3d --> %2d:%2d:%2d,%3d",
      &time_s[0], &time_s[1], &time_s[2], &time_s[3],
      &time_e[0], &time_e[1], &time_e[2], &time_e[3]) ||
      '\n' != fgetc(fin))
    {
      printf("Error: invalid SubRip file\n");
      exit(1);
    }
    prev_seq = seq;
    start = conv_time(time_s);
    end = conv_time(time_e);

    ptail = text;
    while (fgets(ptail, (int)(sizeof(text) - (ptail - text)), fin))
    {
      if ('\n' == *ptail) break;
      ptail += strlen(ptail);
    }
    if (ptail != text) ptail--;
    *ptail = 0;
    if (prev_start != start)
    {
      /*while (ogg_stream_pageout(&os, &og)) // test discontinuous stream support */
      while (ogg_stream_flush(&os, &og))
      {
        if (!ogg_page_write(&og, fout))
        {
          printf("Error: failed writing packet to output stream\n");
          exit(1);
        }
      }
    }
    prev_start = start;
    u8_toutf8(ptail = utf8_text, sizeof(utf8_text), (unsigned short*)wide_text,
      (int)mbstowcs(wide_text, text, sizeof(wide_text) / sizeof(wchar_t)));
    writ_encode_phrase(&ws, &op, (ogg_int64_t)start, end - start, &ptail, 0);
  }
  if (prev_seq)
  {
    op.e_o_s = 1;
    ogg_stream_packetin(&os, &op);
  }
  while (ogg_stream_flush(&os, &og))
  {
    if (!ogg_page_write(&og, fout))
    {
      printf("Error: failed writing packet to output stream\n");
      exit(1);
    }
  }

  writ_encode_clear(&ws);
  fclose(fin);
  fclose(fout);
  return;
}
